package org.learning;

import java.util.Random;

public class A_04 {
    private static class MyQueue {
        private final String[] queue = new String[10];
        // 下一条要存储的位置
        private int putIndex = 0;
        // 下一条要取出的位置
        private int takeIndex = 0;
        // 队列中元素的个数
        private int size = 0;

        private boolean isFull() {
            return size == queue.length;
        }

        private boolean isEmpty() {
            return size == 0;
        }

        public synchronized void put(String message) throws InterruptedException {
            if (isFull()) {
                // 队列已满，等待消费者消费
                wait();
                //利用递归抢锁
                put(message);
            } else {
                put0(message);
            }
        }

        private void put0(String message) {
            queue[putIndex] = message;
            // 通知消费者可以取数据了
            notify();
            size++;
            putIndex = (putIndex + 1) % queue.length;
        }

        public synchronized String take() throws InterruptedException {
            if (isEmpty()) {
                // 队列为空，等待生产者生产
                wait();
                //利用递归抢锁
                return take();
            } else {
                return take0();
            }
        }

        private String take0() {
            String message = queue[takeIndex];
            takeIndex = (takeIndex + 1) % queue.length;
            size--;
            // 通知生产者可以生产了,因为对象锁是当前对象
            notify();
            return message;
        }
    }

    private static class Consumer extends Thread {
        private final MyQueue queue;
        private final Random random = new Random();

        public Consumer(MyQueue queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    String message = queue.take();
                    System.out.println("                Received message: " + message);
                    Thread.sleep(random.nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class Producer extends Thread {
        private final MyQueue queue;
        private int index = 0;
        private final Random random = new Random();

        public Producer(MyQueue queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    String message = "Message " + ++index;
                    queue.put(message);
                    System.out.println("produce message: " + message);
                    Thread.sleep(random.nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        MyQueue queue = new MyQueue();

        for (int i = 0; i < 10; i++) {
            Producer producer = new Producer(queue);
            Consumer consumer = new Consumer(queue);
            producer.start();
            consumer.start();
        }

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.exit(0);
    }
}
